﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Algoritmia.DataStructures.Digraphs;
using Algoritmia.Problems.ShortestPaths.Positive;
using Algoritmia.Utils;
using Demos.ShortestPaths.Dijkstra;

namespace Demos.Problems
{
    public delegate void AristaHandler(Tuple<Vertice, Vertice> arista);
    public delegate void VerticeHandler(Vertice vertice);

    class ObservableDijkstra : DijkstraShortestPathsFinder<Vertice>
    {
        public event AristaHandler AñadirFrontera;
        public event VerticeHandler BorrarFrontera;
        public event AristaHandler AñadirCamino;

        public new IEnumerable<KeyValuePair<Vertice, Vertice>> SomeToSomeBackpointers(IDigraph<Vertice> g, WeightingFunction<Vertice, double> d, IEnumerable<Vertice> sources, IEnumerable<Vertice> targets)
        {
            var distances = _createDistanceMap(g.V);

            foreach (var v in g.V)
            {
                distances[v] = double.PositiveInfinity;
            }
            var inFringeFrom = _createBackpointersMap(g.V);
            foreach (var s in sources)
            {
                distances[s] = 0.0;
                inFringeFrom[s] = s;
            }

            var added = _createSet(g.V);
            int left = targets.Count();
            while (inFringeFrom.Count > 0 && left > 0)
            {
                var keyValuePair = inFringeFrom.ArgMin(kv => distances[kv.Key]);
                var v = keyValuePair.Key;
                //BorrarFrontera(v);
                inFringeFrom.Remove(v);
                added.Add(v);
                //AñadirCamino(new Tuple<Vertice, Vertice>(keyValuePair.Key, keyValuePair.Value));
                yield return keyValuePair;

                if (targets.Contains(v))
                {
                    left--;
                }

                if (left > 0)
                {
                    foreach (var s in g.Successors(v))
                    {
                        if (!added.Contains(s) && distances[v] + d(v, s) < distances[s])
                        {
                            AñadirFrontera(new Tuple<Vertice, Vertice>(v,s));
                            inFringeFrom[s] = v;
                            distances[s] = distances[v] + d(v, s);
                        }
                    }
                }

            }
        }
    }
}
